package com.lecyon.farm.common;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.lecyon.farm.base.RestResponse;
import com.lecyon.farm.comment.JwtUtil;
import com.lecyon.farm.common.constant.CommonConstant;
import com.lecyon.farm.entity.JsSysUser;
import com.lecyon.farm.service.IJsSysRoleService;
import com.lecyon.farm.service.IJsSysUserRoleService;
import com.lecyon.farm.service.IJsSysUserService;
import com.lecyon.farm.util.RedisUtils;
import com.lecyon.farm.util.ResultUtil;
import com.lecyon.farm.util.StringHelper;
import com.lecyon.farm.util.ValidateUtils;
import com.lecyon.farm.vo.request.IdentityCard;
import com.lecyon.farm.vo.request.LoginInfo;
import com.lecyon.farm.vo.request.enums.Sex;
import org.apache.commons.collections.CollectionUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.NumberFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static java.util.stream.Collectors.toList;

/**
 * @author Yao Zheng
 * @Date 2019/8/8 11:11
 */
@Service
public class CommonService {

    private static final Logger LOG = LoggerFactory.getLogger(CommonService.class);

    @Autowired
    @Lazy
    private IJsSysUserService sysUserService;

    @Autowired
    @Lazy
    private IJsSysUserRoleService sysUserRoleService;

    @Autowired
    @Lazy
    private IJsSysRoleService sysRoleService;

    @Autowired
    @Lazy
    private RedisUtils redisUtils;

    /**
     * 固定电话与手机号区分的标志
     */
    public static final String TELEPHONE_FLAG = "-";

    /**
     * 电话（手机）号码规则校验正则表达式
     */
    public static final String MOBILE_NUMBER_REGEX = "^1\\d{10}$";

    /**
     * 电话（固话）号码规则校验正则表达式
     */
    public static final String PHONE_NUMBER_REGEX = "^[0][1-9]{2,3}-[0-9]{5,10}$";

    /**
     * 电话（手机）号码长度规则
     */
    public static final int MOBILE_NUMBER_LENGTH = 11;

    /**
     * E-Mail格式校验正则表达式
     */
    public static final String EMAIL_REGEX = "[\\w\\.\\-]+@([\\w\\-]+\\.)+[\\w\\-]+";

    /**
     * 密码规则正则表达式
     * 重置密码规则 8-12位数字字母组合，不能是纯数字或纯字母
     */
    public static final String PASSWORD_RULE_REGEX = "^(?=.*[a-zA-Z])(?=.*[0-9])[a-zA-Z0-9]{8,12}$";

    /**
     * 密码最小长度
     */
    public static final int PASSWORD_MIN_LENGTH = 8;

    /**
     * 数据脱敏处理的关键长度
     */
    public static final int CONCEAL_SIZE = 6;

    /**
     * 数据脱敏处理的替代符号
     */
    public static final String CONCEAL_SYMBOL = "*";

    /**
     * List去除重复数据,同时去除空对象
     *
     * @param sourceList 源集合
     * @return 去重后的集合
     */
    public synchronized static <T> List<T> getUniqueList(List<T> sourceList) {
        List<T> unique = sourceList.stream().filter(item -> item != null).distinct().collect(toList());
        return unique;
    }

    /**
     * List取差集
     *
     * @param sourceList1 集合1
     * @param sourceList2 集合2
     * @param <T>
     * @return 集合1 - 集合2
     */
    public synchronized static <T> List<T> getDifferenceList(List<T> sourceList1, List<T> sourceList2) {
        List<T> reduce1 = sourceList1.stream().filter(item -> !sourceList2.contains(item)).collect(toList());
        return reduce1;
    }

    /**
     * 大数据量的list拆分
     *
     * @param sourceList 需要拆分的list
     * @param limitSize  拆分后的子list的大小
     * @param <T>
     * @return 子list的集合
     */
    public synchronized static <T> List<List<T>> getPartitionList(List<T> sourceList, int limitSize) {
        List<List<T>> partitionList = Lists.partition(sourceList, limitSize);
        return partitionList;
    }

    /**
     * 获取两个日期的时间差
     *
     * @param startTime
     * @param endTime
     * @param chronoUnit 时间单位（年、月、日、时、分、秒）
     * @return
     */
    public static long betweenTwoTime(LocalDateTime startTime, LocalDateTime endTime, ChronoUnit chronoUnit) {
        Period period = Period.between(LocalDate.from(startTime), LocalDate.from(endTime));
        if (chronoUnit == ChronoUnit.YEARS) {
            return period.getYears();
        }
        if (chronoUnit == ChronoUnit.MONTHS) {
            return period.getYears() * 12 + period.getMonths();
        }
        return chronoUnit.between(startTime, endTime);
    }

    /**
     * 根据生日计算年龄
     *
     * @param birthday 生日
     * @return 年龄
     */
    public static Integer getAge(LocalDate birthday) {
        Integer age = null;
        if (ValidateUtils.isNullOrEmpty(birthday)) {
            return age;
        }
        LocalDate currentDate = LocalDate.now(ZoneId.systemDefault());
        age = birthday.until(currentDate).getYears();
        return age;
    }

    /**
     * 获取一天的开始时间 00:00:00
     *
     * @param localDateTime
     * @return
     */
    public static LocalDateTime getDayStart(LocalDateTime localDateTime) {
        return localDateTime.with(LocalTime.MIN);
    }

    /**
     * 获取一天的结束时间 23:59:59
     *
     * @param localDateTime
     * @return
     */
    public static LocalDateTime getDayEnd(LocalDateTime localDateTime) {
        return localDateTime.with(LocalTime.MAX);
    }

    /**
     * 获取计算后的时间
     *
     * @param date  要计算的时间
     * @param field (年月日时分秒等字段)
     * @param value 传入字段的值
     * @return 计算后的时间
     */
    public static Date getCalculateDate(Date date, int field, int value) {
//        GregorianCalendar gregorianCalendar = new GregorianCalendar();
//        if (ValidateUtils.isNullOrEmpty(date)) {
//            gregorianCalendar.setTime(new Date());
//        } else {
//            gregorianCalendar.setTime(date);
//        }
//        gregorianCalendar.add(field, value);
//        return gregorianCalendar.getTime();
        return null;
    }

    /**
     * 根据传入日期参数，计算日期所在月的第一天
     *
     * @param date 要计算的日期
     * @return 日期所在月份的第一天
     */
    public static Date getFirstDayOfMonthByDate(Date date) {
//        Calendar calendar = Calendar.getInstance();
//        if (ValidateUtils.isNullOrEmpty(date)) {
//            date = new Date();
//        }
//        calendar.setTime(date);
//        int first = calendar.getActualMinimum(Calendar.DAY_OF_MONTH);
//        calendar.set(Calendar.DAY_OF_MONTH, first);
//        return calendar.getTime();
        return null;
    }

    /**
     * 根据传入日期参数，计算日期所在月的最后一天
     *
     * @param date 要计算的日期
     * @return 日期所在月份的最后一天
     */
    public static Date getLastDayOfMonthByDate(Date date) {
//        Calendar calendar = Calendar.getInstance();
//        if (ValidateUtils.isNullOrEmpty(date)) {
//            date = new Date();
//        }
//        calendar.setTime(date);
//        int last = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
//        calendar.set(Calendar.DAY_OF_MONTH, last);
//        return calendar.getTime();
        return null;
    }

    /**
     * 根据传入日期参数，计算日期所在年份的第一天
     *
     * @param date 要计算的日期
     * @return 日期所在年份的第一天
     */
    public static Date getFirstDayOfYearByDate(Date date) {
//        Calendar calendar = Calendar.getInstance();
//        if (ValidateUtils.isNullOrEmpty(date)) {
//            date = new Date();
//        }
//        calendar.setTime(date);
//        int first = calendar.getActualMinimum(Calendar.DAY_OF_YEAR);
//        calendar.set(Calendar.DAY_OF_YEAR, first);
//        return calendar.getTime();
        return null;
    }

    /**
     * 根据传入日期参数，计算日期所在年份的最后一天
     *
     * @param date 要计算的日期
     * @return 日期所在年份的最后一天
     */
    public static Date getLastDayOfYearByDate(Date date) {
//        Calendar calendar = Calendar.getInstance();
//        if (ValidateUtils.isNullOrEmpty(date)) {
//            date = new Date();
//        }
//        calendar.setTime(date);
//        int last = calendar.getActualMaximum(Calendar.DAY_OF_YEAR);
//        calendar.set(Calendar.DAY_OF_YEAR, last);
//        return calendar.getTime();
        return null;
    }

    /**
     * 根据传入日期参数，计算日期属于当年第几周
     *
     * @param date 要计算的日期
     * @return 周
     */
    public static int getWeekOfYearByDate(Date date) {
//        Calendar calendar = Calendar.getInstance();
//        if (ValidateUtils.isNullOrEmpty(date)) {
//            date = new Date();
//        }
//        //设置周一为每周第一天
//        calendar.setFirstDayOfWeek(Calendar.MONDAY);
//        calendar.setTime(date);
//        int week = calendar.get(Calendar.WEEK_OF_YEAR);
//        return week;
        return 0;
    }

    /**
     * 根据传入日期参数，计算所在月份
     *
     * @param date 要计算的日期
     * @return 日期所在月份
     */
    public static int getMonthByDate(Date date) {
//        Calendar calendar = Calendar.getInstance();
//        if (ValidateUtils.isNullOrEmpty(date)) {
//            date = new Date();
//        }
//        calendar.setTime(date);
//        int month = calendar.get(Calendar.MONTH);
//        return month;
        return 0;
    }

    /**
     * 根据传入日期参数，计算所在月份的前一个月
     *
     * @param date 要计算的日期
     * @return 日期所在月份的前一个月
     */
    public static int getLastMonthByDate(Date date) {
//        Calendar calendar = Calendar.getInstance();
//        if (ValidateUtils.isNullOrEmpty(date)) {
//            date = new Date();
//        }
//        calendar.setTime(date);
//        calendar.add(Calendar.MONTH, -1);
//        int lastMonth = calendar.get(Calendar.MONTH);
//        return lastMonth;
        return 0;
    }

    /**
     * 获取上个月
     *
     * @return
     */
    public static Long getLastMonth(Date date) {
//        Calendar calendar = Calendar.getInstance();
//        if (!ValidateUtils.isNullOrEmpty(date)) {
//            calendar.setTime(date);
//        }
//        calendar.add(Calendar.MONTH, -1);
//        return Long.valueOf(DATE_FORMAT_YEAR_MONTH.format(calendar.getTime()));
        return null;
    }

    /**
     * 根据传入日期参数，计算所在月份的下一个月
     *
     * @param date 要计算的日期
     * @return 日期所在月份的下一个月
     */
    public static int getNextMonthByDate(Date date) {
//        Calendar calendar = Calendar.getInstance();
//        if (ValidateUtils.isNullOrEmpty(date)) {
//            date = new Date();
//        }
//        calendar.setTime(date);
//        calendar.add(Calendar.MONTH, 1);
//        int nextMonth = calendar.get(Calendar.MONTH);
//        return nextMonth;
        return 0;
    }

    /**
     * 判断传入的字符串是否是电话号码(手机+固话)
     *
     * @param phoneNumber 电话号码
     * @return 合法性
     */
    public static boolean isPhoneNumber(String phoneNumber) {
        if (StringHelper.isEmpty(phoneNumber)) {
            return false;
        }
        Pattern pattern;
        Matcher matcher;
        boolean isMatch;
        if (phoneNumber.contains(TELEPHONE_FLAG)) {
            //固定电话号码
            pattern = Pattern.compile(PHONE_NUMBER_REGEX);
        } else if (MOBILE_NUMBER_LENGTH == phoneNumber.length()) {
            pattern = Pattern.compile(MOBILE_NUMBER_REGEX);
        } else {
            return false;
        }
        matcher = pattern.matcher(phoneNumber);
        isMatch = matcher.matches();
        return isMatch;
    }

    /**
     * 判断传入的字符串是否是e-mail
     *
     * @param email e-mail
     * @return 合法性
     */
    public static boolean isEmail(String email) {
        if (StringHelper.isEmpty(email)) {
            return false;
        }
        Pattern p = Pattern.compile(EMAIL_REGEX);
        Matcher m = p.matcher(email);
        boolean isMatch = m.matches();
        return isMatch;
    }


    /**
     * 重置密码规则 8-12位数字字母组合，不能是纯数字或纯字母
     *
     * @param password
     * @return
     */
    public static boolean isComplyPasswordRule(String password) {
        if (ValidateUtils.isNullOrEmpty(password)) {
            return false;
        }
        if (PASSWORD_MIN_LENGTH > password.length()) {
            return false;
        } else {
            Pattern p = Pattern.compile(PASSWORD_RULE_REGEX);
            Matcher m = p.matcher(password);
            boolean isMatch = m.matches();
            return isMatch;
        }
    }

    /**
     * 判断字符串是否是满足数据库规定的数字类型
     *
     * @param numberStr 数字字符串
     * @return 合法性
     */
    public static boolean isNumberic(String numberStr) {
        int maxLength = 18;
        if (StringHelper.isEmpty(numberStr)) {
            return false;
        }
        if (numberStr.length() > maxLength) {
            return false;
        }
        StringBuffer buffer = new StringBuffer();
        buffer.append("^[0-9]{1,12}([.][0-9]{1,6})?$");
        Pattern pattern = Pattern.compile(buffer.toString());
        Matcher matcher = pattern.matcher(numberStr);
        boolean flag = matcher.matches();
        return flag;
    }

    /**
     * 判断字符串是否是满足正整数规则的数字类型
     *
     * @param integerStr 数字字符串
     * @return 合法性
     */
    public static boolean isInteger(String integerStr) {
        boolean flag = isNumberic(integerStr);
        if (flag) {
            int maxLength = 10;
            if (integerStr.length() > maxLength) {
                return false;
            }
            Double maxValue = new Double(Integer.MAX_VALUE);
            Double minValue = new Double(Integer.MIN_VALUE);
            Double currentValue = new Double(integerStr);
            if (currentValue > maxValue || currentValue < minValue) {
                return false;
            }
        }
        return flag;
    }

    /**
     * 判断字符串是否是金钱
     *
     * @param moneyStr 价格字符串
     * @return 合法性
     */
    public static boolean isMoney(String moneyStr) {
        boolean flag = isNumberic(moneyStr);
        if (!flag) {
            return false;
        } else {
            BigDecimal money = new BigDecimal(moneyStr);
            int count = BigDecimal.ZERO.compareTo(money);
            return count > 0 ? false : true;
        }
    }

    /**
     * 判断指定的字符串是否是身份证号码
     * <p>
     * 我国公民的身份证号码特点如下
     * 1.长度18位
     * 2.第1-17号只能为数字
     * 3.第18位只能是数字或者x
     * 4.第7-14位表示特有人的年月日信息
     * 请实现身份证号码合法性判断的函数，函数返回值：
     * 1.如果身份证合法返回0
     * 2.如果身份证长度不合法返回1
     * 3.如果第1-17位含有非数字的字符返回2
     * 4.如果第18位不是数字也不是x返回3
     * 5.如果身份证号的出生日期非法返回4
     */
    public static boolean isIDCardNumber(String idCardNumber) {
        if (StringHelper.isEmpty(idCardNumber)) {
            return false;
        }
        int maxLength = 18;
        String regularExpression = "(^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$)|(^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}$)";
        //假设18位身份证号码:41000119910101123X  410001 19910101 123X
        //^开头
        //[1-9] 第一位1-9中的一个      4
        //\\d{5} 五位数字           10001（前六位省市县地区）
        //(18|19|20)                19（现阶段可能取值范围18xx-20xx年）
        //\\d{2}                    91（年份）
        //((0[1-9])|(10|11|12))     01（月份）
        //(([0-2][1-9])|10|20|30|31)01（日期）
        //\\d{3} 三位数字            123（第十七位奇数代表男，偶数代表女）
        //[0-9Xx] 0123456789Xx其中的一个 X（第十八位为校验值）
        //$结尾
        //假设15位身份证号码:410001910101123  410001 910101 123
        //^开头
        //[1-9] 第一位1-9中的一个      4
        //\\d{5} 五位数字           10001（前六位省市县地区）
        //\\d{2}                    91（年份）
        //((0[1-9])|(10|11|12))     01（月份）
        //(([0-2][1-9])|10|20|30|31)01（日期）
        //\\d{3} 三位数字            123（第十五位奇数代表男，偶数代表女），15位身份证不含X
        //$结尾
        boolean matches = idCardNumber.matches(regularExpression);
        //判断第18位校验值
        if (matches) {
            if (maxLength == idCardNumber.length()) {
                try {
                    char[] charArray = idCardNumber.toCharArray();
                    //前十七位加权因子
                    int[] idCardWi = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
                    //这是除以11后，可能产生的11位余数对应的验证码
                    String[] idCardY = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};
                    int sum = 0;
                    for (int i = 0; i < idCardWi.length; i++) {
                        int current = Integer.parseInt(String.valueOf(charArray[i]));
                        int count = current * idCardWi[i];
                        sum += count;
                    }
                    char idCardLast = charArray[17];
                    int idCardMod = sum % 11;
                    if (idCardY[idCardMod].toUpperCase().equals(String.valueOf(idCardLast).toUpperCase())) {
                        return true;
                    } else {
                        LOG.warn("身份证最后一位:" + String.valueOf(idCardLast).toUpperCase() +
                                "错误,正确的应该是:" + idCardY[idCardMod].toUpperCase());
                        return false;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    LOG.warn("异常:" + idCardNumber);
                    return false;
                }
            }

        }
        return matches;
    }

    /**
     * 解析身份证号码信息
     *
     * @param idCardNumber 身份证号码
     * @return 身份证信息
     */
    public static IdentityCard analysisIdCardNumber(String idCardNumber) {
        boolean validateFlag = isIDCardNumber(idCardNumber);
        if (!validateFlag) {
            return null;
        }
        IdentityCard identityCard = new IdentityCard();
        identityCard.setNumber(idCardNumber);
        //解析生日
        String birthdayStr = idCardNumber.substring(6, 14);
        LocalDate birthday = LocalDate.from(DateTimeFormatter.ofPattern("yyyyMMdd").parse(birthdayStr));
        identityCard.setBirthday(birthday);
        //解析年龄
        long age = ChronoUnit.YEARS.between(birthday, LocalDate.now());
        identityCard.setAge(age);
        //解析性别
        int sexFlagBit = 16;
        int divide = 2;
        if (Integer.parseInt(idCardNumber.substring(sexFlagBit).substring(0, 1)) % divide == 0) {
            identityCard.setSex(Sex.FEMALE);
        } else {
            identityCard.setSex(Sex.MALE);
        }
        return identityCard;
    }

    /**
     * 判断指定字符串是否为营业执照 统一社会信用代码（15位/18位）
     *
     * @param license
     * @return
     */
    public synchronized static boolean isLicense(String license) {
        boolean flag = false;
        int length15 = 15;
        int length18 = 18;
        if (StringHelper.isEmpty(license)) {
            return false;
        }
        if (license.length() != length15 && license.length() != length18) {
            return false;
        }
        if (license.length() == length15) {
            flag = isLicense15(license);
        } else if (license.length() == length18) {
            flag = isLicense18(license);
        }
        return flag;

    }

    /**
     * 营业执照 统一社会信用代码（15位）
     *
     * @param license
     * @return
     */
    public synchronized static boolean isLicense15(String license) {
        int length = 15;
        if (StringHelper.isEmpty(license)) {
            return false;
        }
        if (length != license.length()) {
            return false;
        }
        // 获取营业执照注册号前14位数字用来计算校验码
        String businessLicensePre14 = license.substring(0, 14);
        // 获取营业执照号的校验码
        String businessLicense15 = license.substring(14, license.length());
        char[] chars = businessLicensePre14.toCharArray();
        int[] ints = new int[chars.length];
        for (int i = 0; i < chars.length; i++) {
            ints[i] = Integer.parseInt(String.valueOf(chars[i]));
        }
        getCheckCode(ints);
        if (businessLicense15.equals(getCheckCode(ints) + "")) {
            // 比较 填写的营业执照注册号的校验码和计算的校验码是否一致
            return true;
        }
        return false;
    }

    /**
     * 获取 营业执照注册号的校验码
     *
     * @param ints
     * @return
     */
    private synchronized static int getCheckCode(int[] ints) {
        if (null != ints && ints.length > 1) {
            int ti;
            // pi|11+ti
            int si;
            // （si||10==0？10：si||10）*2
            int cj = 0;
            // pj=cj|11==0?10:cj|11
            int pj;
            for (int i = 0; i < ints.length; i++) {
                ti = ints[i];
                pj = (cj % 11) == 0 ? 10 : (cj % 11);
                si = pj + ti;
                cj = (0 == si % 10 ? 10 : si % 10) * 2;
                if (i == ints.length - 1) {
                    pj = (cj % 11) == 0 ? 10 : (cj % 11);
                    return pj == 1 ? 1 : 11 - pj;
                }
            }
        }
        return -1;
    }


    /**
     * 营业执照 统一社会信用代码（18位）
     *
     * @param license
     * @return
     */
    public synchronized static boolean isLicense18(String license) {
        boolean flag;
        int length = 18;
        if (StringHelper.isEmpty(license) || length != license.length()) {
            return false;
        }

        String regex = "^([159Y]{1})([1239]{1})([0-9ABCDEFGHJKLMNPQRTUWXY]{6})([0-9ABCDEFGHJKLMNPQRTUWXY]{9})([0-90-9ABCDEFGHJKLMNPQRTUWXY])$";
        if (!license.matches(regex)) {
            return false;
        }
        // 代码字符集，不含 I O S V Z，共30位
        String baseCode = "0123456789ABCDEFGHJKLMNPQRTUWXY";
        char[] baseCodeArray = baseCode.toCharArray();
        Map<Character, Integer> codes = Maps.newHashMap();
        for (int i = 0; i < baseCode.length(); i++) {
            codes.put(baseCodeArray[i], i);
        }
        char[] businessCodeArray = license.toCharArray();
        Character check = businessCodeArray[17];
        if (baseCode.indexOf(check) == -1) {
            return false;
        }
        int[] wi = {1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, 30, 28};
        int sum = 0;
        for (int i = 0; i < 17; i++) {
            Character key = businessCodeArray[i];
            if (baseCode.indexOf(key) == -1) {
                return false;
            }
            sum += (codes.get(key) * wi[i]);
        }
        int value = 31 - sum % 31;
        if (value == 31) {
            value = 0;
        }
        flag = (value == codes.get(check));
        return flag;
    }

    /**
     * 生成15位随机字符串，根据传入的id
     *
     * @param id        id
     * @param maxLength 生成的最大长度
     * @return
     */
    public synchronized static String createUniqueString(int maxLength, Long id) {
        NumberFormat nf = NumberFormat.getInstance();
        nf.setGroupingUsed(false);
        nf.setMaximumIntegerDigits(maxLength);
        nf.setMinimumIntegerDigits(maxLength);
        String result = nf.format(id);
        return result;
    }

    /**
     * 关键数据脱敏处理
     *
     * @param str 需要脱敏的数据字符串
     * @return 脱敏处理后的字符串
     */
    public synchronized static String toConceal(String str) {
        if (StringHelper.isEmpty(str)) {
            return str;
        }
        int len = str.length();
        int a = len / 2;
        int b = a - 1;
        int c = len % 2;
        StringBuffer sb = new StringBuffer();
        if (len <= 2) {
            if (c == 1) {
                return CONCEAL_SYMBOL;
            }
            sb.append(CONCEAL_SYMBOL);
            sb.append(str.charAt(len - 1));
        } else {
            if (b <= 0) {
                sb.append(str.substring(0, 1));
                sb.append(CONCEAL_SYMBOL);
                sb.append(str.substring(len - 1, len));
            } else if (b >= CONCEAL_SIZE / 2 && CONCEAL_SIZE + 1 != len) {
                int e = (len - CONCEAL_SIZE) / 2;
                sb.append(str.substring(0, e));
                for (int i = 0; i < CONCEAL_SIZE; i++) {
                    sb.append(CONCEAL_SYMBOL);
                    if ((c == 0 && CONCEAL_SIZE % 2 == 0) || (c != 0 && CONCEAL_SIZE % 2 != 0)) {
                        sb.append(str.substring(len - e, len));
                    } else {
                        sb.append(str.substring(len - (e + 1), len));
                    }
                }

            } else {
                int d = len - 2;
                sb.append(str.substring(0, 1));
                for (int i = 0; i < d; i++) {
                    sb.append(CONCEAL_SYMBOL);
                }
                sb.append(str.substring(len - 1, len));
            }
        }
        return sb.toString();
    }

    /**
     * 给排序字段统一添加前缀
     *
     * @param orders 排序字段集合
     * @return List<OrderItem>
     */
    public static List<OrderItem> batchAddPrefix4OrderColumn(List<OrderItem> orders) {
        StringBuffer columns = new StringBuffer();
        if (CollectionUtils.isNotEmpty(orders)) {
            orders.forEach(orderItem -> {
                if (StringHelper.isNotEmpty(orderItem.getColumn())) {
                    columns.delete(0, columns.length());
                    columns.append(CommonConstant.PRE_ORDER_COLUMN).append(orderItem.getColumn());
                    orderItem.setColumn(columns.toString());
                }
            });
        }
        return orders;
    }

    /**
     * 获取当前登录用户id
     *
     * @return
     */
    public Long getCurrentSysUserId() {
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        String key = "currentUserId";
        Long currentUserId = null;
        if (ValidateUtils.isNotNullOrEmpty(session.getAttribute(key))) {
            currentUserId = (Long) session.getAttribute(key);
        }
        if (ValidateUtils.isNullOrEmpty(currentUserId)) {
            currentUserId = CommonConstant.DEFAULT_SYS_USER_ID;
        }
        return currentUserId;
    }

    /**
     * 获取当前租户信息
     *
     * @return
     */
    public static String getCurrentOwner() {
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        String tenantIdKey = "currentOwner";
        String tenantId = (String) session.getAttribute(tenantIdKey);
        if (StringHelper.isNotEmpty(tenantId)) {
            return tenantId;
        } else {
            return CommonConstant.DEFAULT_TENANT_ID;
        }
    }

    /**
     * 切换当前租户为指定租户
     *
     * @param owner
     */
    public static void changeCurrentOwner(String owner) {
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        String tenantIdKey = "currentOwner";
        session.setAttribute(tenantIdKey, owner);
    }

    /**
     * 根据userToken获取当前登录信息
     *
     * @param userToken
     * @return LoginInfo
     */
    public LoginInfo getLoginInfo(String userToken) {
        LoginInfo result = new LoginInfo();
        if (StringHelper.isNotEmpty(userToken)) {
            result.setUserToken(userToken);
        }
        boolean flag = redisUtils.hasKey(userToken);
        if (!flag) {
            return result;
        }
        String sysUserIdStr = JwtUtil.getSysUserId(userToken);
        if (ValidateUtils.isNullOrEmpty(sysUserIdStr)) {
            return result;
        }
        Long sysUserId = Long.parseLong(sysUserIdStr);
        JsSysUser sysUser = sysUserService.getById(sysUserId);
        if (ValidateUtils.isNotNullOrEmpty(sysUser)) {
            result.setSysUser(sysUser);
        }
        List<String> sysRoleList = (List<String>) redisUtils.hGet(sysUserIdStr, "currentUserRoles");
        String sysRole;
        if (CollectionUtils.isNotEmpty(sysRoleList)) {
            sysRole = sysRoleList.get(0);
            result.setRole(sysRole);
        }
        return result;
    }

    /**
     * 根据用户token查找用户信息
     *
     * @param token 用户token
     * @return 用户信息
     */
    public JsSysUser findUserByToken(String token) {
        JsSysUser result = null;
        if (StringHelper.isEmpty(token)) {
            return null;
        }
        StringBuilder key = new StringBuilder();
        key.append(CommonConstant.SYSTEM_NAME).append(CommonConstant.SYSTEM_SPLIT_STR).append(token);
        String tokenKey = key.toString();
        boolean flag = redisUtils.hasKey(tokenKey);
        if (!flag) {
            return null;
        }
        JSON temp = (JSON) redisUtils.get(tokenKey);
        result = JSON.toJavaObject(temp, JsSysUser.class);
        return result;
    }

    /**
     * 验证token令牌的有效性
     *
     * @param token 令牌
     * @return
     */
    private boolean tokenValidation(String token) {
        if (StringHelper.isEmpty(token)) {
            return false;
        }
        //根据token获取sysUserId
        String sysUserId = JwtUtil.getSysUserId(token);
        if (StringHelper.isEmpty(sysUserId)) {
            return false;
        }
        boolean flag = redisUtils.hasKey(sysUserId);
        if (!flag) {
            return false;
        }
        flag = redisUtils.hasKey(token);
        if (!flag) {
            return false;
        }
        return true;
    }

    /**
     * 权限验证
     *
     * @param userToken    被校验的令牌
     * @param restResponse 消息传递对象
     * @return 结果
     */
    public RestResponse permissionValidation(String userToken, RestResponse restResponse) {
        boolean flag = false;
        if (StringHelper.isNotEmpty(userToken)) {
            //令牌有效性校验
            flag = tokenValidation(userToken);
        }
        if (!flag) {
            return ResultUtil.error(restResponse, CommonConstant.EX_FORM_VALIDATE_ERROR, "不是有效的令牌");
        }
        return ResultUtil.success(restResponse, null);
    }

}
